package com.thjk.bdf.common.utils;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class BeanUtil extends BeanUtilsBean {

	private static final Logger log = LoggerFactory.getLogger(BeanUtil.class);

	/**
	 * 
	 * @param dest           目标对象
	 * @param orig           源对象
	 * @param ignoreNullFlag 是否忽略null值
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public void copyProperties(Object dest, Object orig, boolean ignoreNullFlag)
			throws IllegalAccessException, InvocationTargetException {

		// Validate existence of the specified beans
		if (dest == null) {
			throw new IllegalArgumentException("No destination bean specified");
		}
		if (orig == null) {
			throw new IllegalArgumentException("No origin bean specified");
		}
		if (log.isDebugEnabled()) {
			log.debug("BeanUtils.copyProperties(" + dest + ", " + orig + "," + ignoreNullFlag + ")");
		}

		// Copy the properties, converting as necessary
		if (orig instanceof DynaBean) {
			DynaProperty[] origDescriptors = ((DynaBean) orig).getDynaClass().getDynaProperties();
			for (int i = 0; i < origDescriptors.length; i++) {
				String name = origDescriptors[i].getName();
				if (getPropertyUtils().isReadable(orig, name) && getPropertyUtils().isWriteable(dest, name)) {
					Object value = ((DynaBean) orig).get(name);
					if (ignoreNullFlag) {
						if (value != null) {
							copyProperty(dest, name, value);
						}
					} else {
						copyProperty(dest, name, value);
					}
				}
			}
		} else if (orig instanceof Map) {
			@SuppressWarnings("unchecked")
			Map<String, Object> propMap = (Map<String, Object>) orig;
			for (Map.Entry<String, Object> entry : propMap.entrySet()) {
				String name = entry.getKey();
				Object value = entry.getValue();
				if (getPropertyUtils().isWriteable(dest, name)) {
					if (ignoreNullFlag) {
						if (value != null) {
							copyProperty(dest, name, value);
						}
					} else {
						copyProperty(dest, name, value);
					}
				}
			}
		} else {
			PropertyDescriptor[] origDescriptors = getPropertyUtils().getPropertyDescriptors(orig);
			for (int i = 0; i < origDescriptors.length; i++) {
				String name = origDescriptors[i].getName();
				if ("class".equals(name)) {
					continue; // No point in trying to set an object's class
				}
				if (getPropertyUtils().isReadable(orig, name) && getPropertyUtils().isWriteable(dest, name)) {
					try {
						Object value = getPropertyUtils().getSimpleProperty(orig, name);
						if (ignoreNullFlag) {
							if (value != null) {
								copyProperty(dest, name, value);
							}
						} else {
							copyProperty(dest, name, value);
						}
					} catch (NoSuchMethodException e) {
					}
				}
			}
		}
	}

	public static Object mapToObject(Map<String, Object> map, Class<?> beanClass) throws Exception {
		if (map == null)
			return null;

		Object obj = beanClass.newInstance();

		BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
		PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
		for (PropertyDescriptor property : propertyDescriptors) {
			Method setter = property.getWriteMethod();
			if (setter != null) {
				setter.invoke(obj, map.get(property.getName()));
			}
		}

		return obj;
	}

	/**
	 * map 转 bean
	 * @param <T>
	 * @param clazz
	 * @param msg
	 * @return
	 */
	public static <T> T decode(Class<T> clazz, Map<String, String> msg) {
		try {
			T cls = clazz.newInstance();
			java.util.Set<Map.Entry<String, String>> entrySet = msg.entrySet();
			for (Map.Entry<String, String> entry : entrySet) {
				BeanUtils.setProperty(cls, entry.getKey(), entry.getValue());
			}
			return cls;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}